﻿using System;
using System.ComponentModel;
using System.Collections.Specialized;
using Csla.Core;
using System.Reflection;
using BA2009.Utility;

namespace BA2009.Entities
{
    [Serializable()]
    public abstract class EntityBase : IEntity, INotifyPropertyChanged, ICloneable, IDataErrorInfo,IColumnInfo
    {
        [NonSerialized()]
        private PropertyChangedEventHandler nonSerializableHandlers;
        private PropertyChangedEventHandler serializableHandlers;

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged
        {
            add
            {
                if (value.Method.IsPublic && (value.Method.DeclaringType.IsSerializable || value.Method.IsStatic))
                    serializableHandlers = (PropertyChangedEventHandler)System.Delegate.Combine(serializableHandlers, value);
                else
                    nonSerializableHandlers = (PropertyChangedEventHandler)System.Delegate.Combine(nonSerializableHandlers, value);
            }
            remove
            {
                if (value.Method.IsStatic && (value.Method.DeclaringType.IsSerializable || value.Method.IsStatic))
                    serializableHandlers = (PropertyChangedEventHandler)System.Delegate.Remove(serializableHandlers, value);
                else
                    nonSerializableHandlers = (PropertyChangedEventHandler)System.Delegate.Remove(nonSerializableHandlers, value);
            }
        }

        protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler nonSerializableHandlers = this.nonSerializableHandlers;
            if (nonSerializableHandlers != null)
                nonSerializableHandlers.Invoke(this, new PropertyChangedEventArgs(name));

            PropertyChangedEventHandler serializableHanlders = this.serializableHandlers;
            if (serializableHandlers != null)
                serializableHandlers.Invoke(this, new PropertyChangedEventArgs(name));
        }

        #endregion

        public abstract void Validate();

        private bool isSuspend;
        public bool IsSuspendPropertyChanged
        {
            get { return isSuspend; }

            set
            {
                isSuspend = value;

            }

        }

        public int GetPKValue()
        { 
            return Convert.ToInt32(Reflection.GetObjectValue(string.Concat(this.TableName,"ID"),this));
        }

        public int INDEX
        {
            get;
            set;
        }

        public abstract string TableName
        {
            get;
           
        }

        #region ICloneable Members

        public object Clone()
        {
            return Csla.Core.ObjectCloner.Clone(this);
        }

        #endregion

        #region IDataErrorInfo Members

        public string Error
        {
            get { return "hhaha"; }
        }

        public string this[string columnName]
        {
            get { return "hhaha"; }
        }

        #endregion


        #region ColumnInfo

        /// <summary>
        /// Get Property and Attribute of the entity
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public object[,] GetProperties(Type t)
        {

            PropertyInfo[] oProperties = t.GetProperties();
            PropertyInfo oProperty;
            Attribute[] attributes;
            object[,] structureInfo = new object[oProperties.Length, 2];

            try
            {
                for (int i = 0; i < oProperties.Length; i++)
                {
                    oProperty = oProperties[i];
                    attributes = Attribute.GetCustomAttributes(oProperty, typeof(ColumnAttributes), false);
                    structureInfo[i, 0] = oProperty;
                    structureInfo[i, 1] = attributes;
                }
            }
            catch (Exception e) {
                Utility.ExceptionManager.Handle(e);
            }
            return structureInfo;

        }


        /// <summary>
        /// Set value to the fields of the entity
        /// </summary>
        /// <param name="structureInfo"></param>
        /// <param name="oRow"></param>

        public void SetProperties(object[,] structureInfo, object linqEntity)
        {
            PropertyInfo oProperty;
            Attribute[] attributes;

            try
            {

                for (int i = 0; i <= structureInfo.GetUpperBound(0); i++)
                {

                    oProperty = (PropertyInfo)structureInfo[i, 0];
                    attributes = (Attribute[])structureInfo[i, 1];

                    foreach (Attribute attribute in attributes)
                    {
                        ColumnAttributes oColumnAttributeName = (ColumnAttributes)attribute;
                        if (BA2009.Utility.Reflection.GetObjectValue(oColumnAttributeName.ColumnName, linqEntity) != System.DBNull.Value)
                        {
                            oProperty.SetValue(this, BA2009.Utility.Reflection.GetObjectValue(oColumnAttributeName.ColumnName, linqEntity),null);

                            
                        }
                        break;
                    }

                }

            }
            catch (Exception e) { Utility.ExceptionManager.Handle(e); }
            return;

        }



        /// <summary>
        /// Set Linq entity fields
        /// </summary>
        /// <param name="linqEntity"></param>
        public void SetLinqProperties(ref object linqEntity)
        {
            PropertyInfo oProperty;
            Attribute[] attributes;
            var structureInfo = this.GetProperties(this.GetType());

            try
            {

                for (int i = 0; i <= structureInfo.GetUpperBound(0); i++)
                {

                    oProperty = (PropertyInfo)structureInfo[i, 0];
                    attributes = (Attribute[])structureInfo[i, 1];

                    foreach (Attribute attribute in attributes)
                    {
                        ColumnAttributes oColumnAttributeName = (ColumnAttributes)attribute;
                        if (Utility.Reflection.GetObjectValue(oColumnAttributeName.ColumnName, this) != System.DBNull.Value)
                        {
                            //  oProperty.SetValue, BA2009.Utility.Reflection.GetObjectValue(oColumnAttributeName.ColumnName, linqEntity));

                            Utility.Reflection.SetObjectValue(oColumnAttributeName.ColumnName, linqEntity, Utility.Reflection.GetObjectValue(oColumnAttributeName.ColumnName, this));
                        }
                        break;
                    }

                }

            }
            catch (Exception e)
            {
                Utility.ExceptionManager.Handle(e);
            }


        }

        public string GetLinqTypeName()
        {
            return string.Concat("BA2009.DataAccess.Entities.", this.TableName);
        }

        #endregion
    }
}
